作为一名优秀的数据分析师,或多或少都需要了解行业对于自身职业的要求。如果你曾留意一些数据分析的职位要求,你可能看到过这个名词:Tableau。比如今日头条的这条招聘信息

熟悉常用的数据统计和分析方法,熟练使用SQL,Excel,会使用 Tableau 的优先;

Tableau 由于它界面美观、易于操作,受到越来越多特别是互联网公司的亲睐,无论是大到 Facebook、Airbnb 这样的巨型公司,还是像国内 Teambition 这样的创业团队,都能看到 Tableau 的身影。如果你在知乎上关注了 Facebook 邹昕大神的话,你也一定看过他关于“知乎大 V 是如何成为大 V 的?”的回答(什么,你竟然还没有读过?还不快去点赞!),整个分析就是用 Tableau 完成的。

目前 Tableau 2017 年的可视化大赛正在进行中,上海站的比赛刚刚结束(我们曾邀请去年的上海站冠军纪杨老师来优达做分享),这次我们就以今年冠军的作品“Chasing China Dream(圆梦中国)”为案例,展示 Tableau 在可视化方面的过人之处。

对比基础

在这篇文章中,我们用 R(ggplot2) 来和 Tableau 作对比,看看谁可以 方便又快速 地作出美观的图表。得益于ggplot2 的grammar of graphics理念,R 相对于 Python 在作图方面更加流畅,也基于此,优达和 Facebook 一起开发的探索性数据分析课程(Exploratory Data Analysis)使用R作为工具。那么这次 R 和 Tableau 的对决又会有怎样的表现呢?

这次我们将使用 R 的 ggplot2 来模仿 本次上海站冠军 Young Lin 的作品。在作图的过程中,我们尽可能使用自带的功能和最基本的库来对比 Tableau 自带的功能。虽然 R 可以通过小众的插件或是写非常复杂的代码来最大化近似 Tableau 的作图,但这有违我们评比的初衷,毕竟对于大部分分析师来说,更多的精力应该放在分析本身,可视化重要但不应该占用绝大部分的时间。

第一步:数据导入

本次可视化大赛数据格式为 excel,在 R 中我们借用 readxl 导入 excel 文件还算方便,但由于文件中大量字段是中文,如果你的系统环境是英文的话,很有可能会出现乱码的情况,这给数据的导入带来一些麻烦。如果你的R也遇到出现乱码的情况,可以在 R Console 中输入 Sys.setlocale("LC_ALL", 'en_US.UTF-8') 进行编码重置,并点击 File -> Reopen With Encoding。

相对来说,Tableau 的数据导入顺利的多。

Tableau 数据导入

Tableau 数据导入

Tableau 自身支持的文件格式有很多,包括:Excel、Text file (csv, tsv)、JSON 等等,也包括各种 Server。最重要的是,Tableau 对中文的支持非常不错,可以免去数据分析师很多不必要的麻烦。(特别是写 Python 的同学,一定懂我在说什么吧!)

模仿1:模仿投资额与产业的关系图

原图解读

投资额与产业的关系

投资额与产业的关系

这是 Young Lin 的第1张图表,展现的是投资行业与投资金额的关系。这张图表分为两部分,首先是左上角的 Treemap,不同的方块代表不同的投资行业,方块的大小代表投资金额的多少。右下角是投资金额和时间的折线图,与普通折线图不同的是,在每一个折线的点上,都有一个饼图呈现不同行业的投资金额比例。当鼠标移动到对应的数据点时(无论是左上角的 Treemap 还是右下角的饼图或折线图),都会有对应数据的动态交互显现。

值得一提的是,该图中不同行业的颜色选择了渐进色,这点我觉得并不妥当。渐进色常用来表示有层级关系的分类(比如 1~10 的打分,比赛的名次),对于不同的行业名称本身并不存在这样的层级关系。但为方便对比,在用 R 作图时仍采用该渐进色。

图表复现

接下去我们来用 R 复现。由于 ggplot2 原生不支持 treemap,因此在这里使用第三方工具 treemapify 来绘制。(刚开始就要借助第三方工具,哭。。。)

pf.industry <- pf %>% 
  group_by(投资行业) %>% 
  summarise(total.invest = sum(投资金额))

ggplot(pf.industry, aes(area = total.invest, fill = total.invest, label = 投资行业)) +
  geom_treemap() 

treemapify 作 treemap 图非常方便,两行代码就可以搞定,但是默认的视图配色非常难看,且颜色越深反而代表投资金额越少,与直觉不符。因此,在该图的基础上继续调整。

ggplot(pf.industry, aes(area = total.invest, fill = total.invest / 10^9, label = 投资行业)) +
  geom_treemap()  + 
  scale_fill_continuous(low = '#c3e8df', high = '#467a9c',
                           labels = unit_format(unit = "B"),
                        guide = guide_legend(title = "投资额")) #重新设置标签

调整之后,颜色和图例好看了一些,但总觉得没有 Tableau 的配色好看(配色对直男来说真是说不出的痛)。另外,treemap 似乎也没有非常方便地在方块中呈现文字的方式。

接着再来看折线图。在 R 中很难方便地作出折线图和饼图的结合(在此再次感叹一下 Tableau 丰富的可视化表现形式,看上去就觉得很高级),因此退而求其次来画堆积柱状图。

pf.industry.year <- pf %>% 
  mutate(invest.year = strftime(投资时间, "%Y")) %>%  # 将投资时间拆分出来
  group_by(投资行业, invest.year) %>% 
  summarise(total.invest = sum(投资金额))

ggplot(pf.industry.year, aes(x = invest.year, y = total.invest / 10^9, fill = 投资行业)) +
  geom_bar(stat = 'identity', color = "grey") + 
  scale_y_continuous(labels = unit_format(unit = "B")) +
  labs(x = "", y = "投资金额") +
  scale_fill_grey()

我们可以看到,堆积柱状图基本展示了 Tableau 折线+饼图所呈现的信息,柱状图的高度代表每年的总投资额,色块的长度代表每个分类的投资额。但由于分类过多,将柱状图的颜色和图例的文字联系起来有点困难。而在这个方面,Tableau 的优势更加体现出来,将鼠标移至对应的图形上就可以弹出对应的行业分类和金额,非常方便 。

移动鼠标弹出数值

移动鼠标弹出数值

(上图为动图)

模仿2:投资轮次、投资机构和金额的关系图

原图解读

投资轮次、投资机构和金额

投资轮次、投资机构和金额

这张图所展示的是在不同的投资轮次中,不同投资机构的投资占比。左右两边呈现的形式类似,左边是种子轮到E轮的数据,右边是F轮到 M&A 的数据(也包含 Others)。左上角还有一个下拉框筛选不同的投资行业,柱状图会根据不同的筛选而变化。

图表复现

在原始的 excel 表格中,投资轮次并没有被分组整合,因此在作图之前我们需要基于以下关系做数据清洗。

  • 种子轮:种子轮
  • 天使轮:天使轮
  • A轮:‘A+轮’, ‘A轮’, ‘Pre-A轮’
  • B轮:‘B+轮’, ‘B轮’
  • C轮:C轮
  • D轮:D轮
  • E轮:E轮

在 R 中,我们使用的方式是嵌套 ifelse 判断。

而在 Tableau 中,数据重命名优势马上可以体现出来,简单的拖拽即可实现,再多的分组都可以轻松搞定。

对数据进行重命名 (上图为动图)

以下是 R 实现的代码,行数略微有些多。

pf.round.investor <- pf %>% 
  mutate(投资轮次.组合 = ifelse(is.element(投资轮次, c('A+轮', 'A轮', 'Pre-A轮')), 'A轮',
                         ifelse(is.element(投资轮次, c('B+轮', 'B轮')), 'B轮',
                         ifelse(投资轮次 == 'C轮', 'C轮', 
                         ifelse(投资轮次 == 'D轮', 'D轮', 
                         ifelse(投资轮次 == '种子轮', '种子轮',
                         ifelse(投资轮次 == 'E轮', 'E轮',
                         ifelse(投资轮次 == '天使轮', '天使轮', 'other')))))))) %>% 
  group_by(投资轮次.组合, 机构名称) %>% 
  summarise(金额 = sum(投资金额)) %>% 
  group_by(百分比 = 金额 / sum(金额))

pf.round.investor$投资轮次.组合 <- factor(pf.round.investor$投资轮次.组合,
                c('种子轮', '天使轮', 'A轮', 'B轮', 'C轮', 'D轮', 'E轮', 'other'))

ggplot(subset(pf.round.investor, 投资轮次.组合 != 'other'), 
       aes(x = 投资轮次.组合, y = 百分比, fill = 机构名称)) +
  geom_bar(stat = 'identity') +
  scale_fill_brewer(palette = 'Paired') +
  scale_y_continuous(labels = percent) +
  geom_text(aes(label = 机构名称, family = 'PingFang SC Light'), 
            position = position_stack(vjust = 0.5), check_overlap = TRUE, size = 3)

我们用 R 大体上还原了这张关系图,但在细节上还有一些不足。比如,Tableau 在柱状图上的文字可以根据背景颜色的深浅自动变换成黑字或者白字,来让读者看起来更清晰。另外,它也隐藏了一些拥挤色块上的文字,使图表显得更加整洁。这两点虽然是细节,但在 R 中处理起来比较费劲。另外一点,Tableau 里可以非常方便地设置下拉框来筛选展示的数据,这点在 R 中虽然可以做,但需要使用 Shiny 的功能,对大部分分析师来说会比较麻烦。

模仿3:时间、地点与投资额的关系图

原图解读

时间、地点与投资额

时间、地点与投资额

这张图 Tableau 再下一程,在前图下拉框的基础上增加了左边热力图与右边地图的联动,从年、月、行业、省份、投资金额多个方面呈现。只需点击左侧任意方块,该方块投资金额对应的省份就会呈现在右边。

图表复现

这张图左边的复现并不复杂,使用 ggplot2 自带的 geom_tile 即可完成热力图的绘制。


pf.year.month <- pf %>% 
  select(投资时间, 投资金额) %>% 
  mutate(年 = strftime(投资时间, '%Y'),
         月 = strftime(投资时间, '%m')) %>% 
  group_by(年, 月) %>% 
  summarise(金额.总和 = sum(投资金额))



ggplot(pf.year.month, aes(x = 月, y = 年)) +
  geom_tile(aes(fill = 金额.总和 / 10^9)) +
  theme(text = element_text(family = 'PingFang SC Light'))+
  scale_fill_continuous(low = '#c3e8df', high = '#467a9c',
                           labels = unit_format(unit = "B"),
                        guide = guide_legend(title = "金额.总和")) 

这张图的难点是如何快速实现左侧热力图与右侧地图的联动。在 R 中只能通过 Shiny 来实现,相对于 Tableau 几步即可实现的联动功能,Shiny 要花的时间要多的多。

模仿4:不同行业的投资回报率的关系图

原图解读

投资回报率

投资回报率

这张图中规中矩,下方的散点图由不同的图形代表不同的行业,绝大部分都集中在底部,显得比较杂乱,并没有特别多的信息可以解读。另外,由于分类较多,图形已有重复(比如圆形同时代表了SNS社交网络和本地生活),读者解读起来也非常困难。因此,对这幅图的复现主要针对于上方的横向柱状图。

图表复现

这张图用 R 复现起来比较容易,首先依然是对数据的组合与清洗:

  • Seed:A+轮,A轮,B+轮,B轮,C轮,D轮,E轮,Pre-A轮,天使轮,种子轮
  • IPO:F轮-上市前, IPO上市, IPO上市后
  • M&A:并购100%, 并购59%, 并购60%, 并购65%, 并购72%, 并购93%
  • M&A < 50%:并购,并购15%, 并购35%, 并购37%
  • Others:不明确, 战略投资

就像之前演示的,在这方面 Tableau 操作起来依然有很大的优势。

pf.roi <- pf %>% 
  mutate(投资轮次.组合 = 
        ifelse(is.element(投资轮次, c('并购100%', '并购59%', '并购60%', '并购65%', '并购72%', '并购93%')),
                              'M&A',
        ifelse(is.element(投资轮次, c('并购','并购15%', '并购35%', '并购37%')), 'M&A < 50%',
        ifelse(is.element(投资轮次, c('不明确', '战略投资')), 'Others',
        ifelse(is.element(投资轮次, c('F轮-上市前', 'IPO上市', 'IPO上市后')), 'IPO', 'Seed'))))) %>%
  group_by(投资轮次.组合, 投资行业) %>%
  summarise(平均ROI = mean(回报率),
            投资金额.汇总 = sum(投资金额)) #简单起见,直接取平均值

pf.roi$投资轮次.组合 <- factor(pf.roi$投资轮次.组合, c('Seed', 'IPO', 'M&A', 'M&A < 50%', 'Others'))

avg.roi <- mean(pf.roi$平均ROI)
  
ggplot(pf.roi, aes(x = 投资行业, y = 平均ROI)) +
  geom_bar(stat = 'identity') +
  scale_y_continuous(labels = percent) +
  facet_grid(.~投资轮次.组合) +
  geom_hline(yintercept = avg.roi, alpha = 0.3) +
  coord_flip()
  

作图方面,R 在这个图上并没有太大问题,纵向是不同的投资行业,横向是不同的投资阶段和ROI数值,浅色的直线代表平均的ROI。

模仿5:投资领域数量与投资回报的关系图

原图解读

投资领域数量与投资回报

投资领域数量与投资回报

这张图特别是左侧的部分是所有图表中我最喜欢的一张,你可能也已经发现,在左侧的面积图中间空白处放置了说明标签,方便整洁地展现了不同投资机构投资的领域数量,有限的空间呈现了足够多的信息,但又不会觉得冗杂。

在 R 中虽然可以同样作出面积图,但中间内嵌标签却非常困难。在这一方面 Tableau 完胜!

总结

最后我们总结一下两者的优劣对比:

Tableau 的优势:

  1. 操作简便,不需要写代码,简单地拖拽即可实现
  2. 配色美观,图表样式多样,不用再头痛用什么颜色啦
  3. 图表交互性好,特别是联动功能,可以最大程度地提升可视化的表现力

R 的优势:

  1. 比较全能,分析的整个流程都可以做(当然也需要写代码)
  2. 可以通过 notebook 记录整个分析的流程,方便内部存档和交流
  3. 数据量大仍然有办法处理

通过对比,我们发现 Tableau 在可视化方面相对于 R 拥有很大的优势,特别适合互联网公司较快地工作节奏,可以在很短的时间内做出美观易用的图表。当然,R 虽然上手比 Tableau 更难一些,但它的能力更加全面,也能应对可视化之外的许多问题。

总之,如果你需要通过可视化将你的成果展现给老板或同事的话,Tableau 将会是你的第一选择。

Life is short. Use Tableau.

LS0tCnRpdGxlOiAi5pWw5o2u5YiG5p6Q5biI5aaC5L2V5b+r6YCf5L2c5Ye65aW955yL55qE5Zu+6KGoIgpzdWJ0aXRsZTogIlRhYmxldSDkuI4gUiDlr7nmr5QiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcucGF0aCA9ICJwaWMvIikKYGBgCgpgYGB7ciBlY2hvPUZBTFNFfQpsaWJyYXJ5KHJlYWR4bCkgIyDor7vlj5YgZXhjZWwKbGlicmFyeShkcGx5cikgIyDmlbDmja7lpITnkIYKbGlicmFyeShnZ3Bsb3QyKSAjIOS9nOWbvgpsaWJyYXJ5KHRyZWVtYXBpZnkpICMg6Z2i56ev5Zu+CmxpYnJhcnkoZ2d0aGVtZXMpICMg5L+u5pS55Zu+6KGo5qC35byPCmxpYnJhcnkoc2NhbGVzKSAjIOWNleS9jeaYvuekuuWkhOeQhgp0aGVtZV9zZXQodGhlbWVfbWluaW1hbChiYXNlX2ZhbWlseSA9ICdQaW5nRmFuZyBTQyBMaWdodCcpKSAjIOiuvue9ruS4u+mimOWSjOWtl+S9kwpgYGAKCuS9nOS4uuS4gOWQjeS8mOengOeahOaVsOaNruWIhuaekOW4iO+8jOaIluWkmuaIluWwkemDvemcgOimgeS6huino+ihjOS4muWvueS6juiHqui6q+iBjOS4mueahOimgeaxguOAguWmguaenOS9oOabvueVmeaEj+S4gOS6m+aVsOaNruWIhuaekOeahOiBjOS9jeimgeaxgu+8jOS9oOWPr+iDveeci+WIsOi/h+i/meS4quWQjeivje+8mioqVGFibGVhdSoq44CC5q+U5aaC5LuK5pel5aS05p2h55qEW+i/meadoeaLm+iBmOS/oeaBr10oaHR0cHM6Ly93d3cubGFnb3UuY29tL2pvYnMvMzI0NTE0OC5odG1sKe+8mgoKPiDnhp/mgonluLjnlKjnmoTmlbDmja7nu5/orqHlkozliIbmnpDmlrnms5XvvIznhp/nu4Pkvb/nlKhTUUzvvIxFeGNlbO+8jOS8muS9v+eUqCAqKlRhYmxlYXUqKiDnmoTkvJjlhYjvvJsgCgpUYWJsZWF1IOeUseS6juWug+eVjOmdoue+juinguOAgeaYk+S6juaTjeS9nO+8jOWPl+WIsOi2iuadpei2iuWkmueJueWIq+aYr+S6kuiBlOe9keWFrOWPuOeahOS6suedkO+8jOaXoOiuuuaYr+Wkp+WIsCBGYWNlYm9va+OAgUFpcmJuYiDov5nmoLfnmoTlt6jlnovlhazlj7jvvIzov5jmmK/lg4/lm73lhoUgVGVhbWJpdGlvbiDov5nmoLfnmoTliJvkuJrlm6LpmJ/vvIzpg73og73nnIvliLAgVGFibGVhdSDnmoTouqvlvbHjgILlpoLmnpzkvaDlnKjnn6XkuY7kuIrlhbPms6jkuoYgRmFjZWJvb2sg6YK55piV5aSn56We55qE6K+d77yM5L2g5Lmf5LiA5a6a55yL6L+H5LuW5YWz5LqO4oCcW+efpeS5juWkpyBWIOaYr+WmguS9leaIkOS4uuWkpyBWIOeahO+8n10oaHR0cHM6Ly93d3cuemhpaHUuY29tL3F1ZXN0aW9uLzI0NDg5NjE3L2Fuc3dlci8xNTcwMTMyODEp4oCd55qE5Zue562U77yI5LuA5LmI77yM5L2g56uf54S26L+Y5rKh5pyJ6K+76L+H77yf6L+Y5LiN5b+r5Y6754K56LWe77yB77yJ77yM5pW05Liq5YiG5p6Q5bCx5piv55SoIFRhYmxlYXUg5a6M5oiQ55qE44CCCgrnm67liY0gVGFibGVhdSAyMDE3IOW5tOeahOWPr+inhuWMluWkp+i1m+ato+WcqOi/m+ihjOS4re+8jOS4iua1t+ermeeahOavlOi1m+WImuWImue7k+adn++8iOaIkeS7rOabvumCgOivt+WOu+W5tOeahOS4iua1t+ermeWGoOWGm+e6quadqOiAgeW4iFvmnaXkvJjovr7lgZrliIbkuqtdKGh0dHA6Ly93d3cuYmlsaWJpbGkuY29tL3ZpZGVvL2F2MTA1ODc4NzgvKSnvvIzov5nmrKHmiJHku6zlsLHku6Xku4rlubTlhqDlhpvnmoTkvZzlk4HigJxDaGFzaW5nIENoaW5hIERyZWFt77yI5ZyG5qKm5Lit5Zu977yJ4oCd5Li65qGI5L6L77yM5bGV56S6IFRhYmxlYXUg5Zyo5Y+v6KeG5YyW5pa56Z2i55qE6L+H5Lq65LmL5aSE44CCCgojIyMg5a+55q+U5Z+656GACgrlnKjov5nnr4fmlofnq6DkuK3vvIzmiJHku6znlKggUihnZ3Bsb3QyKSDmnaXlkowgVGFibGVhdSDkvZzlr7nmr5TvvIznnIvnnIvosIHlj6/ku6UgKirmlrnkvr/lj4jlv6vpgJ8qKiDlnLDkvZzlh7rnvo7op4LnmoTlm77ooajjgILlvpfnm4rkuo5nZ3Bsb3QyIOeahGdyYW1tYXIgb2YgZ3JhcGhpY3PnkIblv7XvvIxSIOebuOWvueS6jiBQeXRob24g5Zyo5L2c5Zu+5pa56Z2i5pu05Yqg5rWB55WF77yM5Lmf5Z+65LqO5q2k77yM5LyY6L6+5ZKMIEZhY2Vib29rIOS4gOi1t+W8gOWPkeeahOaOoue0ouaAp+aVsOaNruWIhuaekOivvueoi++8iEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXPvvInkvb/nlKhS5L2c5Li65bel5YW344CC6YKj5LmI6L+Z5qyhIFIg5ZKMIFRhYmxlYXUg55qE5a+55Yaz5Y+I5Lya5pyJ5oCO5qC355qE6KGo546w5ZGi77yfCgrov5nmrKHmiJHku6zlsIbkvb/nlKggUiDnmoQgZ2dwbG90MiDmnaXmqKHku78gW+acrOasoeS4iua1t+ermeWGoOWGmyBZb3VuZyBMaW4g55qE5L2c5ZOBXShodHRwczovL3B1YmxpYy50YWJsZWF1LmNvbS9wcm9maWxlL3lvdW5nLmxpbiMhL3ZpemhvbWUvQ2hhc2luZ0NoaW5hRHJlYW0vU3RvcnkxKeOAguWcqOS9nOWbvueahOi/h+eoi+S4re+8jOaIkeS7rOWwveWPr+iDveS9v+eUqOiHquW4pueahOWKn+iDveWSjOacgOWfuuacrOeahOW6k+adpeWvueavlCBUYWJsZWF1IOiHquW4pueahOWKn+iDveOAguiZveeEtiBSIOWPr+S7pemAmui/h+Wwj+S8l+eahOaPkuS7tuaIluaYr+WGmemdnuW4uOWkjeadgueahOS7o+eggeadpeacgOWkp+WMlui/keS8vCBUYWJsZWF1IOeahOS9nOWbvu+8jOS9hui/meaciei/neaIkeS7rOivhOavlOeahOWIneiht++8jOavleern+WvueS6juWkp+mDqOWIhuWIhuaekOW4iOadpeivtO+8jOabtOWkmueahOeyvuWKm+W6lOivpeaUvuWcqOWIhuaekOacrOi6q++8jOWPr+inhuWMlumHjeimgeS9huS4jeW6lOivpeWNoOeUqOe7neWkp+mDqOWIhueahOaXtumXtOOAggoKIyMjIOesrOS4gOatpe+8muaVsOaNruWvvOWFpQoK5pys5qyh5Y+v6KeG5YyW5aSn6LWb5pWw5o2u5qC85byP5Li6IGV4Y2Vs77yM5ZyoIFIg5Lit5oiR5Lus5YCf55SoIGByZWFkeGxgIOWvvOWFpSBleGNlbCDmlofku7bov5jnrpfmlrnkvr/vvIzkvYbnlLHkuo7mlofku7bkuK3lpKfph4/lrZfmrrXmmK/kuK3mlofvvIzlpoLmnpzkvaDnmoTns7vnu5/njq/looPmmK/oi7HmlofnmoTor53vvIzlvojmnInlj6/og73kvJrlh7rnjrDkubHnoIHnmoTmg4XlhrXvvIzov5nnu5nmlbDmja7nmoTlr7zlhaXluKbmnaXkuIDkupvpurvng6bjgILlpoLmnpzkvaDnmoRS5Lmf6YGH5Yiw5Ye6546w5Lmx56CB55qE5oOF5Ya177yM5Y+v5Lul5ZyoIFIgQ29uc29sZSDkuK3ovpPlhaUgYFN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsICdlbl9VUy5VVEYtOCcpYCDov5vooYznvJbnoIHph43nva7vvIzlubbngrnlh7sgRmlsZSAtPiBSZW9wZW4gV2l0aCBFbmNvZGluZ+OAggoK55u45a+55p2l6K+077yMVGFibGVhdSDnmoTmlbDmja7lr7zlhaXpobrliKnnmoTlpJrjgIIKCiFbVGFibGVhdSDmlbDmja7lr7zlhaVdKHBpYy9pbXBvcnRfZmlsZS5wbmcpCgpUYWJsZWF1IOiHqui6q+aUr+aMgeeahOaWh+S7tuagvOW8j+acieW+iOWkmu+8jOWMheaLrO+8mkV4Y2Vs44CBVGV4dCBmaWxlIChjc3YsIHRzdinjgIFKU09OIOetieetie+8jOS5n+WMheaLrOWQhOenjSBTZXJ2ZXLjgILmnIDph43opoHnmoTmmK/vvIxUYWJsZWF1IOWvueS4reaWh+eahOaUr+aMgemdnuW4uOS4jemUme+8jOWPr+S7peWFjeWOu+aVsOaNruWIhuaekOW4iOW+iOWkmuS4jeW/heimgeeahOm6u+eDpuOAgu+8iOeJueWIq+aYr+WGmSBQeXRob24g55qE5ZCM5a2m77yM5LiA5a6a5oeC5oiR5Zyo6K+05LuA5LmI5ZCn77yB77yJCgoKYGBge3IgZWNobyA9IEZBTFNFfQpwZiA8LSByZWFkX2V4Y2VsKCdUYWJsZWF1IOWPr+inhuWMluWIhuaekOS6iemcuOi1m+S4iua1t+ermSAtIOaVsOaNri54bHN4JykKIyBzdHIocGYpCiMgc3VtbWFyeShwZikKYGBgCgojIyMg5qih5Lu/Me+8muaooeS7v+aKlei1hOmineS4juS6p+S4mueahOWFs+ezu+WbvgoKIyMjIyDljp/lm77op6Por7sKCiFb5oqV6LWE6aKd5LiO5Lqn5Lia55qE5YWz57O7XShwaWMvaW52ZXN0X2luZHVzdHJ5LnBuZykKCgrov5nmmK8gWW91bmcgTGluIOeahOesrDHlvKDlm77ooajvvIzlsZXnjrDnmoTmmK/mipXotYTooYzkuJrkuI7mipXotYTph5Hpop3nmoTlhbPns7vjgILov5nlvKDlm77ooajliIbkuLrkuKTpg6jliIbvvIzpppblhYjmmK/lt6bkuIrop5LnmoQgVHJlZW1hcO+8jOS4jeWQjOeahOaWueWdl+S7o+ihqOS4jeWQjOeahOaKlei1hOihjOS4mu+8jOaWueWdl+eahOWkp+Wwj+S7o+ihqOaKlei1hOmHkemineeahOWkmuWwkeOAguWPs+S4i+inkuaYr+aKlei1hOmHkemineWSjOaXtumXtOeahOaKmOe6v+Wbvu+8jOS4juaZrumAmuaKmOe6v+WbvuS4jeWQjOeahOaYr++8jOWcqOavj+S4gOS4quaKmOe6v+eahOeCueS4iu+8jOmDveacieS4gOS4qumlvOWbvuWRiOeOsOS4jeWQjOihjOS4mueahOaKlei1hOmHkemineavlOS+i+OAguW9k+m8oOagh+enu+WKqOWIsOWvueW6lOeahOaVsOaNrueCueaXtu+8iOaXoOiuuuaYr+W3puS4iuinkueahCBUcmVlbWFwIOi/mOaYr+WPs+S4i+inkueahOmlvOWbvuaIluaKmOe6v+Wbvu+8ie+8jOmDveS8muacieWvueW6lOaVsOaNrueahOWKqOaAgeS6pOS6kuaYvueOsOOAggoK5YC85b6X5LiA5o+Q55qE5piv77yM6K+l5Zu+5Lit5LiN5ZCM6KGM5Lia55qE6aKc6Imy6YCJ5oup5LqG5riQ6L+b6Imy77yM6L+Z54K55oiR6KeJ5b6X5bm25LiN5aal5b2T44CC5riQ6L+b6Imy5bi455So5p2l6KGo56S65pyJ5bGC57qn5YWz57O755qE5YiG57G777yI5q+U5aaCIDF+MTAg55qE5omT5YiG77yM5q+U6LWb55qE5ZCN5qyh77yJ77yM5a+55LqO5LiN5ZCM55qE6KGM5Lia5ZCN56ew5pys6Lqr5bm25LiN5a2Y5Zyo6L+Z5qC355qE5bGC57qn5YWz57O744CC5L2G5Li65pa55L6/5a+55q+U77yM5Zyo55SoIFIg5L2c5Zu+5pe25LuN6YeH55So6K+l5riQ6L+b6Imy44CCCgojIyMjIOWbvuihqOWkjeeOsAoK5o6l5LiL5Y675oiR5Lus5p2l55SoIFIg5aSN546w44CC55Sx5LqOIGdncGxvdDIg5Y6f55Sf5LiN5pSv5oyBIHRyZWVtYXDvvIzlm6DmraTlnKjov5nph4zkvb/nlKjnrKzkuInmlrnlt6XlhbcgYHRyZWVtYXBpZnlgIOadpee7mOWItuOAgijliJrlvIDlp4vlsLHopoHlgJ/liqnnrKzkuInmlrnlt6XlhbfvvIzlk63jgILjgILjgIIpCgpgYGB7ciB0cmVlbWFwfQpwZi5pbmR1c3RyeSA8LSBwZiAlPiUgCiAgZ3JvdXBfYnko5oqV6LWE6KGM5LiaKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsLmludmVzdCA9IHN1bSjmipXotYTph5Hpop0pKQoKZ2dwbG90KHBmLmluZHVzdHJ5LCBhZXMoYXJlYSA9IHRvdGFsLmludmVzdCwgZmlsbCA9IHRvdGFsLmludmVzdCwgbGFiZWwgPSDmipXotYTooYzkuJopKSArCiAgZ2VvbV90cmVlbWFwKCkgCgpgYGAKCmB0cmVlbWFwaWZ5YCDkvZwgdHJlZW1hcCDlm77pnZ7luLjmlrnkvr/vvIzkuKTooYzku6PnoIHlsLHlj6/ku6XmkJ7lrprvvIzkvYbmmK/pu5jorqTnmoTop4blm77phY3oibLpnZ7luLjpmr7nnIvvvIzkuJTpopzoibLotormt7Hlj43ogIzku6PooajmipXotYTph5Hpop3otorlsJHvvIzkuI7nm7Top4nkuI3nrKbjgILlm6DmraTvvIzlnKjor6Xlm77nmoTln7rnoYDkuIrnu6fnu63osIPmlbTjgIIKCmBgYHtyIHRyZWVtYXAgdXBkYXRlfQpnZ3Bsb3QocGYuaW5kdXN0cnksIGFlcyhhcmVhID0gdG90YWwuaW52ZXN0LCBmaWxsID0gdG90YWwuaW52ZXN0IC8gMTBeOSwgbGFiZWwgPSDmipXotYTooYzkuJopKSArCiAgZ2VvbV90cmVlbWFwKCkgICsgCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICcjYzNlOGRmJywgaGlnaCA9ICcjNDY3YTljJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJCIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIuaKlei1hOminSIpKSAj6YeN5paw6K6+572u5qCH562+CmBgYAoK6LCD5pW05LmL5ZCO77yM6aKc6Imy5ZKM5Zu+5L6L5aW955yL5LqG5LiA5Lqb77yM5L2G5oC76KeJ5b6X5rKh5pyJIFRhYmxlYXUg55qE6YWN6Imy5aW955yL77yI6YWN6Imy5a+555u055S35p2l6K+055yf5piv6K+05LiN5Ye655qE55eb77yJ44CC5Y+m5aSW77yMYHRyZWVtYXBgIOS8vOS5juS5n+ayoeaciemdnuW4uOaWueS+v+WcsOWcqOaWueWdl+S4reWRiOeOsOaWh+Wtl+eahOaWueW8j+OAggoK5o6l552A5YaN5p2l55yL5oqY57q/5Zu+44CC5ZyoIFIg5Lit5b6I6Zq+5pa55L6/5Zyw5L2c5Ye65oqY57q/5Zu+5ZKM6aW85Zu+55qE57uT5ZCI77yI5Zyo5q2k5YaN5qyh5oSf5Y+55LiA5LiLIFRhYmxlYXUg5Liw5a+M55qE5Y+v6KeG5YyW6KGo546w5b2i5byP77yM55yL5LiK5Y675bCx6KeJ5b6X5b6I6auY57qn77yJ77yM5Zug5q2k6YCA6ICM5rGC5YW25qyh5p2l55S75aCG56ev5p+x54q25Zu+44CCCgoKYGBge3IgYmFyLnllYXIuaW5kdXN0cnl9CnBmLmluZHVzdHJ5LnllYXIgPC0gcGYgJT4lIAogIG11dGF0ZShpbnZlc3QueWVhciA9IHN0cmZ0aW1lKOaKlei1hOaXtumXtCwgIiVZIikpICU+JSAgIyDlsIbmipXotYTml7bpl7Tmi4bliIblh7rmnaUKICBncm91cF9ieSjmipXotYTooYzkuJosIGludmVzdC55ZWFyKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsLmludmVzdCA9IHN1bSjmipXotYTph5Hpop0pKQoKZ2dwbG90KHBmLmluZHVzdHJ5LnllYXIsIGFlcyh4ID0gaW52ZXN0LnllYXIsIHkgPSB0b3RhbC5pbnZlc3QgLyAxMF45LCBmaWxsID0g5oqV6LWE6KGM5LiaKSkgKwogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCBjb2xvciA9ICJncmV5IikgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJCIikpICsKICBsYWJzKHggPSAiIiwgeSA9ICLmipXotYTph5Hpop0iKSArCiAgc2NhbGVfZmlsbF9ncmV5KCkKYGBgCgrmiJHku6zlj6/ku6XnnIvliLDvvIzloIbnp6/mn7Hnirblm77ln7rmnKzlsZXnpLrkuoYgVGFibGVhdSDmipjnur8r6aW85Zu+5omA5ZGI546w55qE5L+h5oGv77yM5p+x54q25Zu+55qE6auY5bqm5Luj6KGo5q+P5bm055qE5oC75oqV6LWE6aKd77yM6Imy5Z2X55qE6ZW/5bqm5Luj6KGo5q+P5Liq5YiG57G755qE5oqV6LWE6aKd44CC5L2G55Sx5LqO5YiG57G76L+H5aSa77yM5bCG5p+x54q25Zu+55qE6aKc6Imy5ZKM5Zu+5L6L55qE5paH5a2X6IGU57O76LW35p2l5pyJ54K55Zuw6Zq+44CC6ICM5Zyo6L+Z5Liq5pa56Z2i77yMVGFibGVhdSDnmoTkvJjlir/mm7TliqDkvZPnjrDlh7rmnaXvvIzlsIbpvKDmoIfnp7voh7Plr7nlupTnmoTlm77lvaLkuIrlsLHlj6/ku6XlvLnlh7rlr7nlupTnmoTooYzkuJrliIbnsbvlkozph5Hpop3vvIzpnZ7luLjmlrnkvr8g44CCCgohW+enu+WKqOm8oOagh+W8ueWHuuaVsOWAvF0ocGljL2xlZ2VuZC5naWYpCgrvvIjkuIrlm77kuLrliqjlm77vvIkKCiMjIyDmqKHku78y77ya5oqV6LWE6L2u5qyh44CB5oqV6LWE5py65p6E5ZKM6YeR6aKd55qE5YWz57O75Zu+CgojIyMjIOWOn+Wbvuino+ivuwoKIVvmipXotYTova7mrKHjgIHmipXotYTmnLrmnoTlkozph5Hpop1dKHBpYy9yb3VuZC5pbnZlc3QucG5nKQoK6L+Z5byg5Zu+5omA5bGV56S655qE5piv5Zyo5LiN5ZCM55qE5oqV6LWE6L2u5qyh5Lit77yM5LiN5ZCM5oqV6LWE5py65p6E55qE5oqV6LWE5Y2g5q+U44CC5bem5Y+z5Lik6L655ZGI546w55qE5b2i5byP57G75Ly877yM5bem6L655piv56eN5a2Q6L2u5YiwRei9rueahOaVsOaNru+8jOWPs+i+ueaYr0bova7liLAgTSZBIOeahOaVsOaNru+8iOS5n+WMheWQqyBPdGhlcnPvvInjgILlt6bkuIrop5Lov5jmnInkuIDkuKrkuIvmi4nmoYbnrZvpgInkuI3lkIznmoTmipXotYTooYzkuJrvvIzmn7Hnirblm77kvJrmoLnmja7kuI3lkIznmoTnrZvpgInogIzlj5jljJbjgIIKCiMjIyMg5Zu+6KGo5aSN546wCgoK5Zyo5Y6f5aeL55qEIGV4Y2VsIOihqOagvOS4re+8jOaKlei1hOi9ruasoeW5tuayoeacieiiq+WIhue7hOaVtOWQiO+8jOWboOatpOWcqOS9nOWbvuS5i+WJjeaIkeS7rOmcgOimgeWfuuS6juS7peS4i+WFs+ezu+WBmuaVsOaNrua4hea0l+OAggoKLSDnp43lrZDova7vvJrnp43lrZDova4KLSDlpKnkvb/ova7vvJrlpKnkvb/ova4KLSBB6L2u77yaJ0Er6L2uJywgJ0Hova4nLCAnUHJlLUHova4nCi0gQui9ru+8midCK+i9ricsICdC6L2uJwotIEPova7vvJpD6L2uCi0gROi9ru+8mkTova4KLSBF6L2u77yaRei9rgoK5ZyoIFIg5Lit77yM5oiR5Lus5L2/55So55qE5pa55byP5piv5bWM5aWXIGBpZmVsc2VgIOWIpOaWreOAggoK6ICM5ZyoIFRhYmxlYXUg5Lit77yM5pWw5o2u6YeN5ZG95ZCN5LyY5Yq/6ams5LiK5Y+v5Lul5L2T546w5Ye65p2l77yM566A5Y2V55qE5ouW5ou95Y2z5Y+v5a6e546w77yM5YaN5aSa55qE5YiG57uE6YO95Y+v5Lul6L275p2+5pCe5a6a44CCCgohW+WvueaVsOaNrui/m+ihjOmHjeWRveWQjV0ocGljL2dyb3VwLmdpZikK77yI5LiK5Zu+5Li65Yqo5Zu+77yJCgrku6XkuIvmmK8gUiDlrp7njrDnmoTku6PnoIHvvIzooYzmlbDnlaXlvq7mnInkupvlpJrjgIIKCmBgYHtyIGJhci5yb3VuZC5pbnZlc3Rvcn0KcGYucm91bmQuaW52ZXN0b3IgPC0gcGYgJT4lIAogIG11dGF0ZSjmipXotYTova7mrKEu57uE5ZCIID0gaWZlbHNlKGlzLmVsZW1lbnQo5oqV6LWE6L2u5qyhLCBjKCdBK+i9ricsICdB6L2uJywgJ1ByZS1B6L2uJykpLCAnQei9ricsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMuZWxlbWVudCjmipXotYTova7mrKEsIGMoJ0Ir6L2uJywgJ0Lova4nKSksICdC6L2uJywKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSjmipXotYTova7mrKEgPT0gJ0Pova4nLCAnQ+i9ricsIAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKOaKlei1hOi9ruasoSA9PSAnROi9ricsICdE6L2uJywgCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uo5oqV6LWE6L2u5qyhID09ICfnp43lrZDova4nLCAn56eN5a2Q6L2uJywKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSjmipXotYTova7mrKEgPT0gJ0Xova4nLCAnRei9ricsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uo5oqV6LWE6L2u5qyhID09ICflpKnkvb/ova4nLCAn5aSp5L2/6L2uJywgJ290aGVyJykpKSkpKSkpICU+JSAKICBncm91cF9ieSjmipXotYTova7mrKEu57uE5ZCILCDmnLrmnoTlkI3np7ApICU+JSAKICBzdW1tYXJpc2Uo6YeR6aKdID0gc3VtKOaKlei1hOmHkeminSkpICU+JSAKICBncm91cF9ieSjnmb7liIbmr5QgPSDph5Hpop0gLyBzdW0o6YeR6aKdKSkKCnBmLnJvdW5kLmludmVzdG9yJOaKlei1hOi9ruasoS7nu4TlkIggPC0gZmFjdG9yKHBmLnJvdW5kLmludmVzdG9yJOaKlei1hOi9ruasoS7nu4TlkIgsCiAgICAgICAgICAgICAgICBjKCfnp43lrZDova4nLCAn5aSp5L2/6L2uJywgJ0Hova4nLCAnQui9ricsICdD6L2uJywgJ0Tova4nLCAnRei9ricsICdvdGhlcicpKQoKZ2dwbG90KHN1YnNldChwZi5yb3VuZC5pbnZlc3Rvciwg5oqV6LWE6L2u5qyhLue7hOWQiCAhPSAnb3RoZXInKSwgCiAgICAgICBhZXMoeCA9IOaKlei1hOi9ruasoS7nu4TlkIgsIHkgPSDnmb7liIbmr5QsIGZpbGwgPSDmnLrmnoTlkI3np7ApKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gJ1BhaXJlZCcpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSDmnLrmnoTlkI3np7AsIGZhbWlseSA9ICdQaW5nRmFuZyBTQyBMaWdodCcpLCAKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksIGNoZWNrX292ZXJsYXAgPSBUUlVFLCBzaXplID0gMykKCmBgYAoKCuaIkeS7rOeUqCBSIOWkp+S9k+S4iui/mOWOn+S6hui/meW8oOWFs+ezu+Wbvu+8jOS9huWcqOe7huiKguS4iui/mOacieS4gOS6m+S4jei2s+OAguavlOWmgu+8jFRhYmxlYXUg5Zyo5p+x54q25Zu+5LiK55qE5paH5a2X5Y+v5Lul5qC55o2u6IOM5pmv6aKc6Imy55qE5rex5rWF6Ieq5Yqo5Y+Y5o2i5oiQ6buR5a2X5oiW6ICF55m95a2X77yM5p2l6K6p6K+76ICF55yL6LW35p2l5pu05riF5pmw44CC5Y+m5aSW77yM5a6D5Lmf6ZqQ6JeP5LqG5LiA5Lqb5oul5oyk6Imy5Z2X5LiK55qE5paH5a2X77yM5L2/5Zu+6KGo5pi+5b6X5pu05Yqg5pW05rSB44CC6L+Z5Lik54K56Jm954S25piv57uG6IqC77yM5L2G5ZyoIFIg5Lit5aSE55CG6LW35p2l5q+U6L6D6LS55Yqy44CC5Y+m5aSW5LiA54K577yMVGFibGVhdSDph4zlj6/ku6XpnZ7luLjmlrnkvr/lnLDorr7nva7kuIvmi4nmoYbmnaXnrZvpgInlsZXnpLrnmoTmlbDmja7vvIzov5nngrnlnKggUiDkuK3omb3nhLblj6/ku6XlgZrvvIzkvYbpnIDopoHkvb/nlKggU2hpbnkg55qE5Yqf6IO977yM5a+55aSn6YOo5YiG5YiG5p6Q5biI5p2l6K+05Lya5q+U6L6D6bq754Om44CCCgojIyMg5qih5Lu/M++8muaXtumXtOOAgeWcsOeCueS4juaKlei1hOmineeahOWFs+ezu+WbvgoKIyMjIyDljp/lm77op6Por7sKCiFb5pe26Ze044CB5Zyw54K55LiO5oqV6LWE6aKdXShwaWMvZ2VvLmdpZikKCui/meW8oOWbviBUYWJsZWF1IOWGjeS4i+S4gOeoi++8jOWcqOWJjeWbvuS4i+aLieahhueahOWfuuehgOS4iuWinuWKoOS6huW3pui+ueeDreWKm+WbvuS4juWPs+i+ueWcsOWbvueahOiBlOWKqO+8jOS7juW5tOOAgeaciOOAgeihjOS4muOAgeecgeS7veOAgeaKlei1hOmHkemineWkmuS4quaWuemdouWRiOeOsOOAguWPqumcgOeCueWHu+W3puS+p+S7u+aEj+aWueWdl++8jOivpeaWueWdl+aKlei1hOmHkemineWvueW6lOeahOecgeS7veWwseS8muWRiOeOsOWcqOWPs+i+ueOAggoKCiMjIyMg5Zu+6KGo5aSN546wCgrov5nlvKDlm77lt6bovrnnmoTlpI3njrDlubbkuI3lpI3mnYLvvIzkvb/nlKggYGdncGxvdDJgIOiHquW4pueahCBgZ2VvbV90aWxlYCDljbPlj6/lrozmiJDng63lipvlm77nmoTnu5jliLbjgIIKCmBgYHtyIGhlYXRtYXAueWVhci5tb250aH0KCnBmLnllYXIubW9udGggPC0gcGYgJT4lIAogIHNlbGVjdCjmipXotYTml7bpl7QsIOaKlei1hOmHkeminSkgJT4lIAogIG11dGF0ZSjlubQgPSBzdHJmdGltZSjmipXotYTml7bpl7QsICclWScpLAogICAgICAgICDmnIggPSBzdHJmdGltZSjmipXotYTml7bpl7QsICclbScpKSAlPiUgCiAgZ3JvdXBfYnko5bm0LCDmnIgpICU+JSAKICBzdW1tYXJpc2Uo6YeR6aKdLuaAu+WSjCA9IHN1bSjmipXotYTph5Hpop0pKQoKCgpnZ3Bsb3QocGYueWVhci5tb250aCwgYWVzKHggPSDmnIgsIHkgPSDlubQpKSArCiAgZ2VvbV90aWxlKGFlcyhmaWxsID0g6YeR6aKdLuaAu+WSjCAvIDEwXjkpKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAnUGluZ0ZhbmcgU0MgTGlnaHQnKSkrCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICcjYzNlOGRmJywgaGlnaCA9ICcjNDY3YTljJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJCIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIumHkeminS7mgLvlkowiKSkgCgpgYGAKCui/meW8oOWbvueahOmavueCueaYr+WmguS9leW/q+mAn+WunueOsOW3puS+p+eDreWKm+WbvuS4juWPs+S+p+WcsOWbvueahOiBlOWKqOOAguWcqCBSIOS4reWPquiDvemAmui/hyBTaGlueSDmnaXlrp7njrDvvIznm7jlr7nkuo4gVGFibGVhdSDlh6DmraXljbPlj6/lrp7njrDnmoTogZTliqjlip/og73vvIxTaGlueSDopoHoirHnmoTml7bpl7TopoHlpJrnmoTlpJrjgIIKCiMjIyDmqKHku78077ya5LiN5ZCM6KGM5Lia55qE5oqV6LWE5Zue5oql546H55qE5YWz57O75Zu+CgojIyMjIOWOn+Wbvuino+ivuwoKIVvmipXotYTlm57miqXnjoddKHBpYy9yb2kucG5nKQoK6L+Z5byg5Zu+5Lit6KeE5Lit55+p77yM5LiL5pa555qE5pWj54K55Zu+55Sx5LiN5ZCM55qE5Zu+5b2i5Luj6KGo5LiN5ZCM55qE6KGM5Lia77yM57ud5aSn6YOo5YiG6YO96ZuG5Lit5Zyo5bqV6YOo77yM5pi+5b6X5q+U6L6D5p2C5Lmx77yM5bm25rKh5pyJ54m55Yir5aSa55qE5L+h5oGv5Y+v5Lul6Kej6K+744CC5Y+m5aSW77yM55Sx5LqO5YiG57G76L6D5aSa77yM5Zu+5b2i5bey5pyJ6YeN5aSN77yI5q+U5aaC5ZyG5b2i5ZCM5pe25Luj6KGo5LqGU05T56S+5Lqk572R57uc5ZKM5pys5Zyw55Sf5rS777yJ77yM6K+76ICF6Kej6K+76LW35p2l5Lmf6Z2e5bi45Zuw6Zq+44CC5Zug5q2k77yM5a+56L+Z5bmF5Zu+55qE5aSN546w5Li76KaB6ZKI5a+55LqO5LiK5pa555qE5qiq5ZCR5p+x54q25Zu+44CCCgojIyMjIOWbvuihqOWkjeeOsAoK6L+Z5byg5Zu+55SoIFIg5aSN546w6LW35p2l5q+U6L6D5a655piT77yM6aaW5YWI5L6d54S25piv5a+55pWw5o2u55qE57uE5ZCI5LiO5riF5rSX77yaCgotIFNlZWTvvJpBK+i9ru+8jEHova7vvIxCK+i9ru+8jELova7vvIxD6L2u77yMROi9ru+8jEXova7vvIxQcmUtQei9ru+8jOWkqeS9v+i9ru+8jOenjeWtkOi9rgotIElQT++8mkbova4t5LiK5biC5YmNLCBJUE/kuIrluIIsIElQT+S4iuW4guWQjgotIE0mQe+8muW5tui0rTEwMCUsIOW5tui0rTU5JSwg5bm26LStNjAlLCDlubbotK02NSUsIOW5tui0rTcyJSwg5bm26LStOTMlCi0gTSZBIDwgNTAl77ya5bm26LStLOW5tui0rTE1JSwg5bm26LStMzUlLCDlubbotK0zNyUKLSBPdGhlcnPvvJrkuI3mmI7noa4sIOaImOeVpeaKlei1hAoK5bCx5YOP5LmL5YmN5ryU56S655qE77yM5Zyo6L+Z5pa56Z2iIFRhYmxlYXUg5pON5L2c6LW35p2l5L6d54S25pyJ5b6I5aSn55qE5LyY5Yq/44CCCgpgYGB7ciBiYXIucm9pfQpwZi5yb2kgPC0gcGYgJT4lIAogIG11dGF0ZSjmipXotYTova7mrKEu57uE5ZCIID0gCiAgICAgICAgaWZlbHNlKGlzLmVsZW1lbnQo5oqV6LWE6L2u5qyhLCBjKCflubbotK0xMDAlJywgJ+W5tui0rTU5JScsICflubbotK02MCUnLCAn5bm26LStNjUlJywgJ+W5tui0rTcyJScsICflubbotK05MyUnKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNJkEnLAogICAgICAgIGlmZWxzZShpcy5lbGVtZW50KOaKlei1hOi9ruasoSwgYygn5bm26LStJywn5bm26LStMTUlJywgJ+W5tui0rTM1JScsICflubbotK0zNyUnKSksICdNJkEgPCA1MCUnLAogICAgICAgIGlmZWxzZShpcy5lbGVtZW50KOaKlei1hOi9ruasoSwgYygn5LiN5piO56GuJywgJ+aImOeVpeaKlei1hCcpKSwgJ090aGVycycsCiAgICAgICAgaWZlbHNlKGlzLmVsZW1lbnQo5oqV6LWE6L2u5qyhLCBjKCdG6L2uLeS4iuW4guWJjScsICdJUE/kuIrluIInLCAnSVBP5LiK5biC5ZCOJykpLCAnSVBPJywgJ1NlZWQnKSkpKSkgJT4lCiAgZ3JvdXBfYnko5oqV6LWE6L2u5qyhLue7hOWQiCwg5oqV6LWE6KGM5LiaKSAlPiUKICBzdW1tYXJpc2Uo5bmz5Z2HUk9JID0gbWVhbijlm57miqXnjocpLAogICAgICAgICAgICDmipXotYTph5Hpop0u5rGH5oC7ID0gc3VtKOaKlei1hOmHkeminSkpICPnroDljZXotbfop4HvvIznm7TmjqXlj5blubPlnYflgLwKCnBmLnJvaSTmipXotYTova7mrKEu57uE5ZCIIDwtIGZhY3RvcihwZi5yb2kk5oqV6LWE6L2u5qyhLue7hOWQiCwgYygnU2VlZCcsICdJUE8nLCAnTSZBJywgJ00mQSA8IDUwJScsICdPdGhlcnMnKSkKCmF2Zy5yb2kgPC0gbWVhbihwZi5yb2kk5bmz5Z2HUk9JKQogIApnZ3Bsb3QocGYucm9pLCBhZXMoeCA9IOaKlei1hOihjOS4miwgeSA9IOW5s+Wdh1JPSSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiAgZmFjZXRfZ3JpZCgufuaKlei1hOi9ruasoS7nu4TlkIgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBhdmcucm9pLCBhbHBoYSA9IDAuMykgKwogIGNvb3JkX2ZsaXAoKQogIApgYGAKCuS9nOWbvuaWuemdou+8jFIg5Zyo6L+Z5Liq5Zu+5LiK5bm25rKh5pyJ5aSq5aSn6Zeu6aKY77yM57q15ZCR5piv5LiN5ZCM55qE5oqV6LWE6KGM5Lia77yM5qiq5ZCR5piv5LiN5ZCM55qE5oqV6LWE6Zi25q615ZKMUk9J5pWw5YC877yM5rWF6Imy55qE55u057q/5Luj6KGo5bmz5Z2H55qEUk9J44CCCgojIyMg5qih5Lu/Ne+8muaKlei1hOmihuWfn+aVsOmHj+S4juaKlei1hOWbnuaKpeeahOWFs+ezu+WbvgoKIyMjIyDljp/lm77op6Por7sKCiFb5oqV6LWE6aKG5Z+f5pWw6YeP5LiO5oqV6LWE5Zue5oqlXShwaWMvcmlzay5wbmcpCgrov5nlvKDlm77nibnliKvmmK/lt6bkvqfnmoTpg6jliIbmmK/miYDmnInlm77ooajkuK3miJHmnIDllpzmrKLnmoTkuIDlvKDvvIzkvaDlj6/og73kuZ/lt7Lnu4/lj5HnjrDvvIzlnKjlt6bkvqfnmoTpnaLnp6/lm77kuK3pl7Tnqbrnmb3lpITmlL7nva7kuobor7TmmI7moIfnrb7vvIzmlrnkvr/mlbTmtIHlnLDlsZXnjrDkuobkuI3lkIzmipXotYTmnLrmnoTmipXotYTnmoTpoobln5/mlbDph4/vvIzmnInpmZDnmoTnqbrpl7TlkYjnjrDkuobotrPlpJ/lpJrnmoTkv6Hmga/vvIzkvYblj4jkuI3kvJrop4nlvpflhpfmnYLjgIIKCuWcqCBSIOS4reiZveeEtuWPr+S7peWQjOagt+S9nOWHuumdouenr+Wbvu+8jOS9huS4remXtOWGheW1jOagh+etvuWNtOmdnuW4uOWbsOmavuOAguWcqOi/meS4gOaWuemdoiBUYWJsZWF1IOWujOiDnO+8gQoKIyMjIOaAu+e7kwoK5pyA5ZCO5oiR5Lus5oC757uT5LiA5LiL5Lik6ICF55qE5LyY5Yqj5a+55q+U77yaCgpUYWJsZWF1IOeahOS8mOWKv++8mgoKMS4g5pON5L2c566A5L6/77yM5LiN6ZyA6KaB5YaZ5Luj56CB77yM566A5Y2V5Zyw5ouW5ou95Y2z5Y+v5a6e546wCjIuIOmFjeiJsue+juingu+8jOWbvuihqOagt+W8j+Wkmuagt++8jOS4jeeUqOWGjeWktOeXm+eUqOS7gOS5iOminOiJsuWVpgozLiDlm77ooajkuqTkupLmgKflpb3vvIznibnliKvmmK/ogZTliqjlip/og73vvIzlj6/ku6XmnIDlpKfnqIvluqblnLDmj5DljYflj6/op4bljJbnmoTooajnjrDlipsKClIg55qE5LyY5Yq/77yaCgoxLiDmr5TovoPlhajog73vvIzliIbmnpDnmoTmlbTkuKrmtYHnqIvpg73lj6/ku6XlgZrvvIjlvZPnhLbkuZ/pnIDopoHlhpnku6PnoIHvvIkKMi4g5Y+v5Lul6YCa6L+HIG5vdGVib29rIOiusOW9leaVtOS4quWIhuaekOeahOa1geeoi++8jOaWueS+v+WGhemDqOWtmOaho+WSjOS6pOa1gQozLiDmlbDmja7ph4/lpKfku43nhLbmnInlip7ms5XlpITnkIYKCumAmui/h+WvueavlO+8jOaIkeS7rOWPkeeOsCBUYWJsZWF1IOWcqOWPr+inhuWMluaWuemdouebuOWvueS6jiBSIOaLpeacieW+iOWkp+eahOS8mOWKv++8jOeJueWIq+mAguWQiOS6kuiBlOe9keWFrOWPuOi+g+W/q+WcsOW3peS9nOiKguWlj++8jOWPr+S7peWcqOW+iOefreeahOaXtumXtOWGheWBmuWHuue+juinguaYk+eUqOeahOWbvuihqOOAguW9k+eEtu+8jFIg6Jm954S25LiK5omL5q+UIFRhYmxlYXUg5pu06Zq+5LiA5Lqb77yM5L2G5a6D55qE6IO95Yqb5pu05Yqg5YWo6Z2i77yM5Lmf6IO95bqU5a+55Y+v6KeG5YyW5LmL5aSW55qE6K645aSa6Zeu6aKY44CCCgrmgLvkuYvvvIzlpoLmnpzkvaDpnIDopoHpgJrov4flj6/op4bljJblsIbkvaDnmoTmiJDmnpzlsZXnjrDnu5nogIHmnb/miJblkIzkuovnmoTor53vvIxUYWJsZWF1IOWwhuS8muaYr+S9oOeahOesrOS4gOmAieaLqeOAggoKTGlmZSBpcyBzaG9ydC4gVXNlIFRhYmxlYXUu